// This is JDefenceTower, a simple tower defence style game
//
// Copyright (C) 2010 Maximilian Junker
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 3 of the License, or (at your option) any later
// version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
// details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, see <http://www.gnu.org/licenses/>.

package junker.defence.model;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MoveToSinkBehaviour extends Behaviour {
	/** Distance units per 100 time units */
	private Path	path	= null;
	private Path	oldLocs	= new Path();

	@Override
	protected List<GameRequest> execute(StepSummary s, TimeSpan span) {
		// path is empty ==> goal reached
		if (path != null && path.size() == 0)
			return Collections.<GameRequest> emptyList();

		// The distance we can move in this step
		float distance = (this.getMapObject().getMapObjectDescription()
				.getSpeed()/1000)
				* (span.getDurationMillis());

		// Check if there might be a shorter path now and check if the old path
		// is still valid
		if (null == path || s.isBarrierRemoved() || s.isBarrierCreated()) {
			this.path = this.getMapObject().findPathToSink();
		}
		
		// Calculate the move
		float d = distance;
		MapLocation l = path.peek();
		MapLocation c = this.getMapObject().getLocation();
		while (d > 0) {
			float dp = c.substract(l).getLength();
			if (dp <= d) {
				c = l;
				oldLocs.addFirst(path.poll());
				if (path.size() == 0)
					break;
				else {
					l = path.peek();
					d = d - dp;
				}
			} else {
				c = c.add(l.substract(c).withLength(d));
				d = 0;
			}
		}

		return Arrays.asList((GameRequest) (new MoveRequest(this, this
				.getMapObject(), c)));
	}

	@Override
	public void commit(GameRequest e) {
		oldLocs.clear();
	}

	@Override
	public void conflict(GameRequest e) {
		while (!oldLocs.isEmpty()) {
			path.addFirst(oldLocs.removeFirst());
		}
	}
}
